#include "precomp.h"
#include "pkfuncs.h"
#include "txproc.h"
#include "rxproc.h"
#include "SDCardDDK.h"

/*
 * Check_For_Hang status
 */
typedef enum {
	C4H_NORMAL,					///Normal => no error
	C4H_TX_TIMEOUT,				///Tx-Timeout
	C4H_CMD_TIMEOUT,			///Command-Timeout
	C4H_MAX						///Maximum status
} CK4HNG_STATUS;


///Indicate "Disconnect" to upper layer or not
///Conditions:
///     - If roaming mode is enabled & we are in the middle of roaming => Skip to indicate to the upper layer
BOOLEAN     IsIndicateDisconnect(PMRVDRV_ADAPTER pAdapter)
{
    BOOLEAN     result;

    switch (pAdapter->RoamingMode) {
        case SMLS_ROAMING_MODE:
            if (wlan_roam_query_isConnecting(pAdapter->pwlanRoamParam) == TRUE) {
                result = FALSE;
                break;
            }
            result = TRUE;
            break;
        default:
            result = TRUE;
            break;
    }

    return result;
}

//++dralee_20060327
//only for PPS enabled. when sleepperiod command is set and no queued packets & pending Q
/*
UCHAR CheckLastPacketIndication(IN PMRVDRV_ADAPTER Adapter)
{   
  
   if( (Adapter->sleepperiod) != 0 &&
       ///GetPendingTxPktCount(Adapter->pTxParam) == 0 &&
       (ReadyForNextTxPacket(Adapter->pTxParam) == FALSE) &&
       (Adapter->CurCmd == 0) &&        //dralee_20060706
       IsQEmpty(&Adapter->CmdPendQ) )
       return 1;
   else 
       return 0;

}
*/

NDIS_STATUS
MrvDrvSend(
    IN NDIS_HANDLE MiniportAdapterContext,
    IN PNDIS_PACKET Packet,
    IN UINT Flags)
{
	PMRVDRV_ADAPTER pAdapter = (PMRVDRV_ADAPTER)MiniportAdapterContext;
    NDIS_STATUS Status = NDIS_STATUS_SUCCESS;

    // In Deep Sleep Mode no packet can be sent out 
    //012207
    //if (Adapter->IsDeepSleep)
    if( !IsThisDsState(pAdapter, DS_STATE_NONE) )
    {
      //Status = NDIS_STATUS_NO_CABLE;
      return NDIS_STATUS_FAILURE;
    }
	    //      Check device removal status
    if( pAdapter->SurpriseRemoved == TRUE )    
    {   
        DBGPRINT(DBG_TX|DBG_WARNING,(TEXT("[MrvSend]: NDIS_STATUS_FAILURE by supriseRemoved\r\n")));
        return NDIS_STATUS_FAILURE;
    }

    if( pAdapter->bIsPendingReset == TRUE || pAdapter->ChipResetting == 1)
    {                         
        DBGPRINT(DBG_TX|DBG_CMD|DBG_WARNING,(L"[MrvSend]: NDIS RETURN FAILURE by bIsPendingReset or ChipReset\r\n"));
        return NDIS_STATUS_FAILURE;
    }


    if ( pAdapter->MediaConnectStatus == NdisMediaStateDisconnected )
    {
        DBGPRINT(DBG_TX|DBG_WARNING, (L"***WARNING: OS attempted to send packet while disconnected!\r\n"));
        
        if (IsIndicateDisconnect(pAdapter) == TRUE) {
            Ndis_MediaStatus_Notify(pAdapter,NDIS_STATUS_MEDIA_DISCONNECT); 
        } else {
            NdisMSleep(100000);     ///Sleep 100ms temporally
        }
        //dralee_20060712
        ResetAllScanTypeAndPower(pAdapter);
        /// Have not used the Tx-Node, not needed to reset the stauts
        ///CleanUpSingleTxBuffer(pAdapter->pTxParam);
        ///RxNode is used by RX/CMD/MACEvent if it's SDIO.
        /// => Don't reset the event, or the status may be messed up
        ///ResetRxPDQ(pAdapter->pRxParam); 
        return NDIS_STATUS_FAILURE;
    }                       

	{
		PNDIS_BUFFER  pBuffer;
		UINT            BufferCount;
		UINT           Length;   
		UINT           TotalPacketLength = 0;   
		PVOID           pVirtualAddr;
		PUCHAR            pHeader = NULL;

		// check if in key absent state, if so, block all packet other than
		// 802.1x
		if ( (pAdapter->EncryptionStatus == Ndis802_11Encryption2KeyAbsent )|| (pAdapter->EncryptionStatus == Ndis802_11Encryption3KeyAbsent ) )  
		{
			///pTxNode = &Adapter->TxNode;
        
			NdisQueryPacket( 
			        Packet,
			        NULL,
			        &BufferCount,
			        &pBuffer,
			        &TotalPacketLength );

			if (!pBuffer || !BufferCount || !TotalPacketLength)
			{
				return NDIS_STATUS_FAILURE;

			}

			NdisQueryBuffer(pBuffer, &pVirtualAddr, &Length);
			pHeader = (PUCHAR)pVirtualAddr;

			if ( TotalPacketLength < 14 ) 
			{
				// malformed packet, blocked!
				DBGPRINT(DBG_TX|DBG_WARNING,(L"Got packet with size less than 14 bytes, reject!\n"));
				return NDIS_STATUS_FAILURE;
			}

			if ( (pHeader[12] != 0x88) || (pHeader[13] != 0x8E) )
			{
				DBGPRINT(DBG_TX|DBG_WARNING,(L"Still no key and packet type(0x%x 0x%x)is not 802.1x , drop!\n",
                                  pHeader[12],
                                  pHeader[13]));
				return NDIS_STATUS_FAILURE;
			}
		}// if ( (Adapter->EncryptionStatus == Ndis802_11Encryption2KeyAbsent )|| (Adapter->EncryptionStatus == Ndis802_11Encryption3KeyAbsent ) )  
	}

	{
		PNDIS_BUFFER  pBuffer;
		UINT            BufferCount;
		UINT           Length;   
		UINT           TotalPacketLength = 0;   
		PVOID           pVirtualAddr;
		PUCHAR            pHeader = NULL;
		
		if(pAdapter->TCloseWZCFlag==WZC_Ignore_Send_EAPOL_START)
		{
		 if ( (pAdapter->EncryptionStatus == Ndis802_11Encryption2Enabled )||
		 	  (pAdapter->EncryptionStatus == Ndis802_11Encryption2KeyAbsent )||
		 	  (pAdapter->EncryptionStatus == Ndis802_11Encryption3Enabled )||
		 	  (pAdapter->EncryptionStatus == Ndis802_11Encryption3KeyAbsent )  )  
		    {
		        ///pTxNode = &Adapter->TxNode;
		        
		        NdisQueryPacket( 
		            Packet,
		            NULL,
		            &BufferCount,
		            &pBuffer,
		            &TotalPacketLength );

		      if (!pBuffer || !BufferCount || !TotalPacketLength)
		      {
		        return NDIS_STATUS_FAILURE;
		        
		      }

		       NdisQueryBuffer(pBuffer, &pVirtualAddr, &Length);
		       pHeader = (PUCHAR)pVirtualAddr;


		        if ( (pHeader[12] == 0x88) && (pHeader[13] == 0x8E)&& (pHeader[14] == 0x01) &&(pHeader[15] == 0x01) )
		        {
		            DBGPRINT(DBG_TX|DBG_HELP,(L"Temporary don't send EAPOL-start!!EncryptionStatus=0x%x, (0x%x, 0x%x, 0x%x, 0x%x)\n",
		                                  pAdapter->EncryptionStatus, 
					             pHeader[12],
		                                  pHeader[13],
		                                  pHeader[14],
		                                  pHeader[15]));
		            return NDIS_STATUS_SUCCESS;
		        }
		 	}
		}
	}
	Status = TxSend(pAdapter->pTxParam, Packet, Flags);
    if (Status == NDIS_STATUS_SUCCESS) {
		///Enhance_PS ++
        /// EnhancePS is: don't follow the DTIM rule. If the device is sleeping while a packet is ready, wake it up
		if (pAdapter->ehancePS == TRUE) {
			if(pAdapter->bPSConfirm == TRUE) {
				if( IsThisHostPowerState(pAdapter, HTWK_STATE_SLEEP) || 
					(  !IsThisHostPowerState(pAdapter, HTWK_STATE_SLEEP) &&  
					   pAdapter->psState == PS_STATE_SLEEP &&
					   pAdapter->PPS_Enabled == 0 && 
					   pAdapter->sleepperiod ==0  )  )
				 {
				   DBGPRINT(DBG_HOSTSLEEP|DBG_WARNING,(L"SendSinglePacket: Pwr up device\r\n"));
				   If_PowerUpDevice(pAdapter);
				 }
			}
		
		}
		///Enhance_PS --
        SetTxSoftIntr(pAdapter);
    }
    return Status;
}


/******************************************************************************
 *
 *  Name: MrvDrvReturnPacket()
 *
 *  Description: the rx ndis return packet callback function (handler) 
 *
 *  Arguments:  Packet : the packet Ndis return
 *    
 *  Notes:        
 *
 *****************************************************************************/

VOID
MrvDrvReturnPacket(
    IN NDIS_HANDLE  MiniportAdapterContext,
    IN PNDIS_PACKET Packet)
{
  PMRVDRV_ADAPTER Adapter = (PMRVDRV_ADAPTER)MiniportAdapterContext;

    //RETAILMSG(1, (L"====>%s: Return_Packet\r\n", TEXT(__FUNCTION__)));
  ///if (Adapter->sNumOutstandingRxPacket)
  if (GetRxPendPktcnt(Adapter->pRxParam)) {
      ReturnRxPacketDesc(Adapter->pRxParam, Packet);
  } else {
    RETAILMSG(1, (L"%s: Not return PKT\r\n", TEXT(__FUNCTION__)));
  }

  //RETAILMSG(1,(TEXT("[Marvell]-MrvDrvReturnPacket")));
  return;
}

 


